package io.jsen.meta.diff;

import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;
import io.jsen.meta.diff.feature.annotation.MetaFieldFeature;
import io.jsen.meta.diff.obj.MetaObject;
import io.jsen.meta.diff.watch.MetaChangeWalker;
import io.jsen.meta.diff.watch.MetaPath;
import io.jsen.meta.diff.watch.MetaPathSearch;
import io.jsen.meta.diff.watch.MetaTreePrint;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static io.jsen.meta.diff.context.DefaultMetaContext.instance;

/**
 * @author jsen
 * @date 2021/4/6
 */
public class Demo {
    private static MetaChangeWalker.Walker walker = new MetaChangeWalker.Walker() {
        @Override
        public boolean stopWalk(MetaObject metaObject) {
            return false;
        }

        @Override
        public void print(MetaObject metaObject) {
            System.out.println(metaObject);
        }
    };

    public static void main(String[] args) {
        diffMan();

        Map<String, String> map1 = new HashMap<>();
        map1.put("name", "jsen");
        map1.put("age", "12");
        Map<String, String> map2 = new HashMap<>();
        map2.put("name", "jack");
        map2.put("sex", "女");
        MetaObject diffObject = instance.diffMeta(
                new TypeToken<Map<String, String>>() {
                }, map1, map2
        );
        Object nativeObject = instance.toNative(diffObject);

//
        List<String> array1 = Lists.newArrayList("hello", "world");
        List<String> array2 = Lists.newArrayList("hello", "jsen");
        MetaObject obj3 = instance.diffMeta(
                new TypeToken<List<String>>() {
                }, array1, array2
        );
        MetaObject obj4 = instance.diffMeta(
                new TypeToken<TEnum>() {
                }, TEnum.AGE, TEnum.COLOR
        );
        MetaObject obj5 = instance.diffMeta(
                new TypeToken<Integer>() {
                }, null, null
        );
        Object n5 = instance.toNative(obj5);
        Sex s1 = new Sex(1, new Sex(2, null));
        Sex s2 = new Sex(2, new Sex(3, null));
        MetaObject obj6 = instance.diffMeta(
                TypeToken.of(Sex.class), s1, s2
        );
        Object nSex = instance.toNative(obj6);
        System.out.println("ok");
    }

    private static void diffMan() {
        Man newMan = new Man(1L, 27, 100L, Lists.newArrayList(1L, 2L), TEnum.AGE,
                LocalDateTime.now());
        Man oldMan = new Man(1L, null, 100L, Lists.newArrayList(2L), TEnum.COLOR,
                LocalDateTime.now());
        MetaObject oLoad = instance.toMeta(TypeToken.of(Man.class), newMan);
        MetaObject obj = instance.diffMeta(TypeToken.of(Man.class), newMan, oldMan);
        MetaTreePrint.print(obj, System.out::println);
        Object o = instance.toNative(obj);
        MetaChangeWalker.walk(obj, walker);
        MetaPath path = MetaPath.builder(true).p("tEnum").build();
        MetaObject tEnum = MetaPathSearch.search(obj, path);

        Map<String, Man> manMap1 = new HashMap<>();
        manMap1.put("man", newMan);
        Map<String, Man> manMap2 = new HashMap<>();
        manMap2.put("man", oldMan);
        TypeToken typeToken = new TypeToken<Map<String, Man>>() {
        };
        MetaObject objManDiff = instance.diffMeta(typeToken, manMap1, manMap2);
        Object objMan = instance.toNative(objManDiff);
    }

    public enum TEnum {
        AGE,
        COLOR
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Man {
        @MetaFieldFeature(uniqueKey = true)
        private Long id;
        @MetaFieldFeature(ignore = true)
        private Integer age;
        private Long high;
        @MetaFieldFeature(alias = "支持")
        private List<Long> support;
        @MetaFieldFeature(alias = "颜色")
        private TEnum tEnum;
        private LocalDateTime time;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Sex {
        private int sex;
        private Sex sexI;
    }
}
